﻿using System.IO;
using BomComparison.Core.Interface;
using BomComparison.Core.Model;
using OfficeOpenXml;

namespace Excel.EPPlus;

/// <summary>
/// 实现 IExcelReader 接口用于从 Excel 文件读取 BOM 数据
/// </summary>
public class ExcelReader : IExcelReader
{
    // 定义常量以提高代码可读性和可维护性
    private const int START_COL_INDEX = 1; // Excel 列索引从 1 开始
    private const int TITLE_ROW_OFFSET = 1; // 数据行相对于标题行的偏移量

    // 属性定义，用于存储 Excel 文件路径和列映射信息
    public string ExcelFilePath { get; set; } // Excel 文件路径
    public int TitleRow { get; set; } // 标题行的行号
    public int PartNumberCol { get; set; } // 零件号列的列号
    public int PartQtyCol { get; set; } // 零件数量列的列号
    public int PartRefDesCol { get; set; } // 零件位号列的列号
    public int PartDescriptionCol { get; set; } // 零件描述列的列号
    public List<BomItem> BillOfMaterials { get; set; } // 存储读取的 BOM 数据

    // 默认构造函数
    public ExcelReader()
    {
        // 初始化属性或执行其他必要的初始化操作
    }

    #region 实现IExcelReader接口
    /// <summary>
    /// 从指定的 Excel 文件读取数据并返回 BOM 列表
    /// </summary>
    /// <param name="excelFilePath">Excel 文件路径</param>
    /// <param name="bomHeaderMap">BOM 列头映射信息</param>
    /// <returns>包含 BOM 数据的列表</returns>
    public List<BomItem> ReadData(string excelFilePath, BomHeaderMap bomHeaderMap)
    {
        if (string.IsNullOrWhiteSpace(excelFilePath))
        {
            throw new ArgumentException("Excel file path cannot be null or empty.", nameof(excelFilePath));
        }

        if (bomHeaderMap == null)
        {
            throw new ArgumentNullException(nameof(bomHeaderMap), "BOM header map cannot be null.");
        }

        ExcelFilePath = excelFilePath;

        try
        {
            ReadAndPopulateBOM(bomHeaderMap);
        }
        catch (Exception ex)
        {
            // 捕获异常并重新抛出，附加更多上下文信息
            throw new InvalidOperationException($"Failed to read data from Excel file: {excelFilePath}", ex);
        }

        return BillOfMaterials;
    }
    #endregion

    #region 使用Epplus从xlsx文件读取BOM 转为list
    /// <summary>
    /// 使用 EPPlus 库从 Excel 文件中读取 BOM 数据并填充到列表中
    /// </summary>
    /// <param name="bomHeaderMap">BOM 列头映射信息</param>
    private void ReadAndPopulateBOM(BomHeaderMap bomHeaderMap)
    {
        try
        {
            // 设置 EPPlus 的许可为非商业许可
            ExcelPackage.License.SetNonCommercialPersonal("ZHJEE");

            // 创建 Excel 文件信息对象
            FileInfo xlsxFile = new(ExcelFilePath);
            if (!xlsxFile.Exists)
            {
                throw new FileNotFoundException($"Excel file not found: {ExcelFilePath}");
            }

            // 使用 EPPlus 打开 Excel 文件
            using ExcelPackage package = new(xlsxFile);
            // 获取第一个工作表
            var worksheet = package.Workbook.Worksheets[0];

            // 检查工作表是否为空或未正确格式化
            if (worksheet == null || worksheet.Dimension == null)
            {
                throw new ArgumentException("The worksheet is empty or not properly formatted.");
            }

            // 获取工作表的最大行数和列数
            var maxRows = worksheet.Dimension.End.Row;
            var maxCols = worksheet.Dimension.End.Column;

            // 检查行和列索引是否有效
            if (maxRows <= bomHeaderMap.TitleRow || maxCols <= START_COL_INDEX)
            {
                throw new ArgumentException("工作表区域无效，无法读取数据。");
            }

            // 初始化 BOM 列表
            BillOfMaterials = new List<BomItem>();

            // 优化：提前读取整个区域的值，减少重复读取
            var rangeValues = worksheet.Cells[bomHeaderMap.TitleRow + TITLE_ROW_OFFSET, START_COL_INDEX, maxRows, maxCols];

            // 遍历数据行并提取 BOM 数据
            for (int rowIndex = bomHeaderMap.TitleRow + TITLE_ROW_OFFSET; rowIndex <= maxRows; rowIndex++)
            {
                var bomItem = CreateBomItemFromRow(rangeValues, rowIndex, bomHeaderMap);
                if (bomItem != null)
                {
                    BillOfMaterials.Add(bomItem);
                }
            }
        }
        catch (Exception ex)
        {
            // 捕获异常并输出错误信息
            Console.WriteLine(ex.Message);
        }
    }


    /// <summary>
    /// 从 Excel 行中创建 BOM 项目
    /// </summary>
    /// <param name="rangeValues">Excel 单元格范围</param>
    /// <param name="rowIndex">当前行索引</param>
    /// <param name="bomHeaderMap">BOM 列头映射信息</param>
    /// <returns>创建的 BOM 项目</returns>
    private BomItem? CreateBomItemFromRow(ExcelRange rangeValues, int rowIndex, BomHeaderMap bomHeaderMap)
    {
        try
        {
            var partNumber = GetCellTextOrEmpty(rangeValues[rowIndex, bomHeaderMap.PartNumberCol]);
            var partQuantity = GetCellFloat(rangeValues[rowIndex, bomHeaderMap.QuantityCol]);
            var partReference = GetCellTextOrEmpty(rangeValues[rowIndex, bomHeaderMap.ReferenceDesignatorCol]);
            var partDescription = GetCellTextOrEmpty(rangeValues[rowIndex, bomHeaderMap.DescriptionCol]);

            return new BomItem
            {
                PartNumber = partNumber,
                PartQuantity = partQuantity,
                PartReference = partReference,
                PartDescription = partDescription
            };
        }
        catch (FormatException ex)
        {
            Console.WriteLine($"Error processing row {rowIndex}: {ex.Message}");
            return null;// 跳过该行
        }
    }
    #endregion

    /// <summary>
    /// 获取单元格的文本值，如果为空则返回空字符串
    /// </summary>
    /// <param name="cell">Excel 单元格</param>
    /// <returns>单元格的文本值</returns>
    private static string GetCellTextOrEmpty(ExcelRange cell)
    {
        //if (cell.IsRichText)
        //{
        //    // 如果单元格包含富文本，返回其文本值
        //    return cell.RichText.Text ?? string.Empty;
        //}
        //else
        //{
        //    // 否则返回单元格的值转换为字符串
        //    return Convert.ToString(cell.Value) ?? string.Empty;
        //}

        //不要使用Value属性，否则如果单元戈有富文本会受到样式干扰
        return cell?.Text?.Trim() ?? string.Empty;
    }

    /// <summary>
    /// 获取单元格的浮点值，如果转换失败则返回 0
    /// </summary>
    /// <param name="cell">Excel 单元格</param>
    /// <returns>单元格的浮点值</returns>
    private static float GetCellFloat(ExcelRange cell)
    {
        var qtyInput = GetCellTextOrEmpty(cell);

        if (float.TryParse(qtyInput, out float result))
        {
            return result;
        }
        // 如果转换失败，输出错误信息
        Console.WriteLine($"Failed to parse float value at cell {cell?.Address}: {cell?.Text}");
        // 抛出异常，明确指出问题所在
        throw new FormatException($"Failed to parse float value at cell {cell?.Address}: {qtyInput}");
    }
}






